package com.feng.study.demo.stream.thread;

import com.feng.study.model.Product;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


/**
 *
 * submit和execute的区别：
 * submit有返回值，而execute没有
 * 用到返回值的例子，比如说有很多个做数据验证的task，希望所有的task执行完，然后每个task告诉我它的执行结果，如果失败，原因是什么，然后把所有失败的原因综合起来返回。
 * submit方便Exception处理
 * 如果想在外边能够感知到task内部的exception，就需只能用submit，并捕获Future.get抛出的异常。
 * 比如说有很多更新数据的task，希望如果其中一个task失败，其它的task就不需要执行了。那就需要catch Future.get抛出的异常，然后终止其它task的执行。
 *
 * 同样submit方法，参数Runnable和Callable也稍微有些不同：
 * 当将Callable的对象传递给ExecutorService的submit方法，则该call方法自动在一个线程上执行，并且会返回执行结果Future对象。
 * 当将Runnable的对象传递给ExecutorService的submit方法，则该run方法自动在一个线程上执行，并且会返回执行结果Future对象，但是在该Future对象上调用get方法，将返回null。
 *
 */
public class ThreadPoolDemo {

    private static final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("thread-pool-demo--%d").build();

    private static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 5, 1, TimeUnit.MINUTES, new LinkedBlockingDeque<>(),
            threadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());

    public static void main(String[] args) throws InterruptedException {
        Product product1 = new Product().setName("aaa");
        Product product2 = new Product().setName("bbb");
        Product product3 = new Product().setName("ccc");
        List<Product> products = Lists.newArrayList(product1,product2,product3);

        for (Product product : products) {
            Future<Product> future = poolExecutor.submit(new Callable<Product>() {
                @Override
                public Product call() throws Exception {
                    ThreadLocal<Product> threadLocal = new ThreadLocal<>();
                    threadLocal.set(product);
                    //业务逻辑
                    dealProduct(threadLocal);
                    return product;
                }
            });
            // 优化线程之间的调度延迟，使用Future来等待任务完成而不是Sleep
            try {
                future.get(1, TimeUnit.SECONDS); // 设置超时时间以避免无限等待
            } catch (Exception e) {
                // 处理任务执行过程中的异常
                e.printStackTrace();
                System.out.println("异常发生----"+product.getName());
                System.out.println(e.getMessage());
                future.cancel(true); // 取消任务
            }
        }
        System.out.println("开始");
        for (Product product : products) {
            poolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    ThreadLocal<Product> threadLocal = new ThreadLocal<>();
                    threadLocal.set(product);
                    //业务逻辑
                    dealProduct(threadLocal);
                }
            });
            Thread.sleep(1000);
        }
        System.out.println("结束");
    }

    /**
     * 业务处理
     *
     * @param threadLocal
     */
    private static void dealProduct(ThreadLocal<Product> threadLocal) {
        System.out.println("业务处理");
        Product product = threadLocal.get();
        System.out.println("product:" + product);
        if (product.getName().equals("bbb")){
            throw new NullPointerException();
        }
    }
}
